package com.common.base.tools.utils.file

import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.os.Build
import android.os.Environment
import androidx.core.content.PermissionChecker
import com.common.base.tools.utils.ApplicationUtils
import com.common.base.tools.utils.logger
import io.reactivex.Observable
import java.io.*


object FileUtil {

    fun getStorePath(storageEnum: StorageEnum): String {
        return when (storageEnum) {
            StorageEnum.STORAGE_DATA_FILES -> {
                ApplicationUtils.context().filesDir.path
            }

            StorageEnum.STORAGE_DATA_CACHE -> {
                ApplicationUtils.context().cacheDir.path
            }

            StorageEnum.STORAGE_SDCARD_ANDROID_FILES -> {
                ApplicationUtils.context().getExternalFilesDir(Environment.DIRECTORY_PODCASTS)?.path
                    ?: ""
            }

            StorageEnum.STORAGE_SDCARD_ANDROID_CACHE -> {
                ApplicationUtils.context().externalCacheDir?.path ?: ""
            }

            StorageEnum.STORAGE_SDCARD -> {
                Environment.getExternalStorageDirectory().path
            }

            else -> {
                ApplicationUtils.context().filesDir.path
            }
        }

    }

    /**
     * 创建文件
     * @param dirName 目录
     * @param fileName 文件名
     */
    fun createFile(filePath: String, isReplace: Boolean = false): File? {
        return try {
            var file = File(filePath)
            createFile(file, isReplace)
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

    /**
     * 创建文件
     * @param dirName 目录
     * @param fileName 文件名
     */
    fun createFile(dirName: String, fileName: String, isReplace: Boolean = false): File? {
        return try {
            var file = File("$dirName/$fileName")
            createFile(file, isReplace)
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }


    /**
     * 创建文件
     * @param file
     */
    fun createFile(file: File, isReplace: Boolean = false): File? {
        try {
            if (isReplace)
                fileDelete(file, isReplace)
            val isSucc = file.createNewFile()
            if (isSucc)
                return file
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * 创建文件
     * @param StorageEnum 存储位置
     * @param fileName 文件名字
     * @param subDir 子路径目录
     * @param isReplace 是否替换
     */
    fun createFile(
        storageEnum: StorageEnum,
        fileName: String,
        subDir: String? = "",
        isReplace: Boolean = false
    ): File? {
        var subDirPath = ""
        if (!subDir.isNullOrEmpty()) {
            subDirPath = "/$subDir"
            createFileDir(storageEnum, subDir)
        }
        try {
            val dirName = getStorePath(storageEnum) + subDirPath
            val file = File(dirName, fileName)
            return createFile(file, isReplace)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * 创建目录
     * @param StorageEnum 存储位置
     * @param fileDirName 目录名字
     */
    fun createFileDir(
        storageEnum: StorageEnum,
        fileDirName: String? = "",
        isReplace: Boolean = false
    ): File? {
        try {
            val file = File(getStorePath(storageEnum), fileDirName)
            fileDelete(file, isReplace)
            return if (!file.exists()) {
                val mkdirs = file.mkdirs()
                if (mkdirs) {
                    logger.info("目录创建成功:${file.absolutePath}")
                    file
                } else {
                    logger.info("目录创建失败:${file.absolutePath}")
                    null
                }
            } else {
                file
            }
        } catch (e: Exception) {
            logger.error(e.message, e)
            e.printStackTrace()
        }
        return null
    }

    /**
     * 文件是否存在
     */
    fun fileExist(file: File?): Boolean {
        if (file?.exists() == true)
            return true
        return false
    }

    /**
     *删除文件
     */
    fun fileDelete(file: File?, isReplace: Boolean) {
        if (fileExist(file) && isReplace) {

            if (file?.delete() == true)
                logger.info("删除成功:${file.absolutePath}")
            else
                logger.info("删除失败:${file?.absolutePath}")
        }

    }


    /**
     * 文件存储
     *
     * @param file  文件
     * @param bytes 字节
     */
    fun writeFile(file: File, bytes: ByteArray) {
        var out: FileOutputStream? = null
        try {
            out = FileOutputStream(file, true)
            out.write(bytes)
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            if (out != null) {
                try {
                    out.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }
    }

    /**
     * 文件存储
     *
     * @param file  文件
     * @param bytes 字节
     */
    fun writeFile(file: File, content: String) {
        var out: FileOutputStream? = null
        try {
            out = FileOutputStream(file, true)
            out.write(content.toByteArray())
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            if (out != null) {
                try {
                    out.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }
    }

    /**
     * 文件读取
     *
     * @param file  文件
     * @param bytes 字节
     */
    fun readFile(file: File): String {
        var res: String = ""
        try {
            val fin: FileInputStream = FileInputStream(file)
            val length = fin.available()
            val buffer = ByteArray(length)
            fin.read(buffer)
            res = String(buffer)
            fin.close()
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
            logger.error("文件读取异常", e)
        }
        return res
    }

    /**
     * 返回当前机器的SD卡的状态是否可用
     */
    fun checkSdCardExists(): Boolean {
        try {
            val sdState = Environment.getExternalStorageState()
            if (Environment.MEDIA_MOUNTED != sdState) {
                // SD卡状态不可用的情况下
                logger.error("SD卡状态不可用")
                return false
            }
            return true
        } catch (e: Exception) {
            e.printStackTrace()
            return false
        }
    }

    /**
     * 判定是否有读写权限
     * 权限校验是否通过
     */
    fun checkPermissionReadWrite(): Boolean {
        val result: Boolean
        val ctx = ApplicationUtils.context()
        result = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // WRITE_EXTERNAL_STORAGE 获取到的同时会获取到READ_EXTERNAL_STORAGE
            ctx.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
        } else {
            PermissionChecker.checkSelfPermission(
                ctx,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            ) == PermissionChecker.PERMISSION_GRANTED
        }
        return result
    }

    /**
     * 图片压缩
     * @param srcFile 图片
     * @param threshold 转化的边界值
     * @param forceAlpha 是否强制透明，透明文件对应的是png格式的文件
     */
    fun requestPicCompressObservable(
        srcFile: File,
        threshold: Int,
    ): Observable<File> {
        return if (!srcFile.exists()) {
            // 文件路径不存在的情况
            Observable.error<File>(FileNotFoundException("文件路径有误"))
        } else {
            Observable.just(
                srcFile
            ).flatMap {
                // 需要进行压缩了
                val options = BitmapFactory.Options()
                options.inJustDecodeBounds = true
                options.inSampleSize = 1
                // 防止溢出
                FileInputStream(it).use { input ->
                    // 此处有options的赋值逻辑
                    BitmapFactory.decodeStream(input, null, options)
                }
                val width = options.outWidth
                val height = options.outHeight
                //  取长边，调整一下处理过程中对于压缩边对取舍问题，改为只取宽
//			val longSize = width.coerceAtLeast(height)
                if (threshold > 0 || threshold < width) {
                    var compressImg =
                        "${srcFile.parent}/${srcFile.nameWithoutExtension}_$threshold.jpg"
                    logger.info("压缩图片的路径：\n$compressImg")
                    // 需要进行压缩计算
                    // 第一步创建输出File路径
                    var outFile: File? = createFile(compressImg)
                    outFile = compress(it, outFile!!, threshold, width, false)
                    if (outFile == null) {
                        Observable.error(IOException("文件压缩过程中出现未知异常"))
                    } else
                        Observable.just(outFile)
                } else {
                    // 无需压缩的情况下
                    Observable.just(it)
                }
            }
        }
    }


    /**
     * 具体的压缩实现代码
     *
     * @param srcFile 具体可来源的压缩文件
     * @param outFile 输出文件的路径
     * @param threshold 转化的边界值
     * @param longSize 最大边
     * @param forceAlpha 是否强制透明，透明文件对应的是png格式的文件
     */
    @Throws(IOException::class)
    private fun compress(
        srcFile: File,
        outFile: File?,
        threshold: Int,
        longSize: Int,
        forceAlpha: Boolean
    ): File? {
        if (outFile == null)
            return outFile
        val options = BitmapFactory.Options()
        // 具体的压缩比例，详情参考(https://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize)
        // 算法上长边/界限
        options.inSampleSize = compressSize(threshold, longSize)
        // 压缩完成之后再恢复
        options.inJustDecodeBounds = false
        var targetBitmap: Bitmap?
        FileInputStream(srcFile).use {
            targetBitmap = BitmapFactory.decodeStream(it, null, options)
        }
        // 第一步：缩放图片
        if (targetBitmap == null)
            return null
//    var targetBitmap = BitmapFactory.decodeStream(FileInputStream(srcFile), null, options)
//        ?: // 如果为空，其实只要输入流不为空，不会出现这个情况

        // 输出流
        val steam = ByteArrayOutputStream()
        // 横竖图的切换处理
        // 部分拍照的图片得出的横竖比例是不对应的
        val orientation = getPicRotation(srcFile.absolutePath)
        if (orientation > 0) {
            val matrix = Matrix()
            matrix.postRotate(orientation.toFloat())
            targetBitmap = Bitmap.createBitmap(
                targetBitmap!!,
                0,
                0,
                targetBitmap!!.width,
                targetBitmap!!.height,
                matrix,
                true
            )
        }
        // 透明度处理，非透明度特殊需求的可能将PNG转换成JPEG -- JPEG的图片更加小
        targetBitmap!!.compress(
            if (forceAlpha) Bitmap.CompressFormat.PNG else Bitmap.CompressFormat.JPEG,
            70,
            steam
        )
        targetBitmap!!.recycle() // 回收
        // 输出到文件流
        FileOutputStream(outFile).use {
            it.write(steam.toByteArray())
            steam.close()
        }
        return outFile
    }

    private fun compressSize(threshold: Int, longSize: Int): Int {
        // 计算出最大边和预期长的比例
        val scale = longSize / threshold
        logger.info("压缩比例为: $scale")
        return scale
    }

    private fun getPicRotation(filePath: String): Int {
        val exifInterface = androidx.exifinterface.media.ExifInterface(filePath)
        return when (exifInterface.getAttributeInt(
            androidx.exifinterface.media.ExifInterface.TAG_ORIENTATION,
            -1
        )) {
            androidx.exifinterface.media.ExifInterface.ORIENTATION_ROTATE_90 -> 90
            androidx.exifinterface.media.ExifInterface.ORIENTATION_ROTATE_180 -> 180
            androidx.exifinterface.media.ExifInterface.ORIENTATION_ROTATE_270 -> 270
            else -> 0
        }
    }
}